﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
using System.Text.RegularExpressions;
using Microsoft.Crm.Sdk.Messages;

namespace OptionsetEditor
{
    public partial class OptionsetEditor : XrmToolBox.PluginBase
    {
        public OptionsetEditor()
        {
            InitializeComponent();
        }

        private void chkIsGlobal_CheckedChanged(object sender, EventArgs e)
        {
            if (chkIsGlobal.Checked)
            {
                cboEntities.Enabled = false;
                cboOptionSets.Enabled = true;
                LoadGlobalOptionSets();
            }
            else
            {
                cboEntities.Enabled = true;
                cboOptionSets.Enabled = false;
                LoadEntities();
            }
        }

        private void LoadEntities()
        {
        }

        private void LoadGlobalOptionSets()
        {
            WorkAsync("Retrieving global optionsets...",
                (e) =>
                {
                    cboOptionSets.Items.Clear();
                    RetrieveAllOptionSetsRequest retrieveAllOptionSetsRequest = new RetrieveAllOptionSetsRequest();
                    RetrieveAllOptionSetsResponse retrieveAllOptionSetsResponse = (RetrieveAllOptionSetsResponse)Service.Execute(retrieveAllOptionSetsRequest);
                    if (retrieveAllOptionSetsResponse.OptionSetMetadata != null
                        && retrieveAllOptionSetsResponse.OptionSetMetadata.Length > 0)
                    {
                        var optionsets = new Dictionary<string, string>();
                        foreach (var om in retrieveAllOptionSetsResponse.OptionSetMetadata)
                        {
                            if (om.IsCustomizable.Value == true)
                            {
                                cboOptionSets.Items.Add(new Item(
                                        string.Format("{0} ({1})", om.DisplayName.LocalizedLabels.FirstOrDefault().Label, om.Name),
                                        om.Name)
                                    );
                            }
                        }
                    }
                },
                e =>
                {
                }
            );
        }

        private void LoadSelectedEntityOptionSets()
        {
        }

        private void LoadSelectedOptionSetOptions()
        {
            WorkAsync("Retrieving global optionsets...",
                (e) =>
                {
                    var req = new RetrieveOptionSetRequest()
                        {
                            Name = ((Item)cboOptionSets.SelectedItem).Value,
                        };
                    var resp = (RetrieveOptionSetResponse)Service.Execute(req);
                    OptionSetMetadata md = (OptionSetMetadata)resp.OptionSetMetadata;
                    if (md.Options != null
                        && md.Options.Count > 0)
                    {
                        var items = new List<Item>();
                        foreach (var item in md.Options)
                        {
                            items.Add(new Item(
                                    item.Label.LocalizedLabels.FirstOrDefault().Label,
                                    item.Value.ToString()
                                ));
                        }

                        dgvOptions.Rows.Clear();
                        dgvOptions.AutoGenerateColumns = false;

                        dgvOptions.Columns[0].DataPropertyName = "Name";
                        dgvOptions.Columns[1].DataPropertyName = "Value";

                        dgvOptions.DataSource = new BindingList<Item>(items);
                    }
                },
                e =>
                {
                }
            );
        }

        private void cboEntities_SelectedIndexChanged(object sender, EventArgs e)
        {
            cboOptionSets.Enabled = true;
            LoadSelectedEntityOptionSets();
        }

        private void cboOptionSets_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadSelectedOptionSetOptions();
        }

        private class Item
        {
            [DisplayName("Label")]
            public string Name { get; set; }

            [DisplayName("Value")]
            public string Value { get; set; }

            public Item(string name, string value)
            {
                Name = name; Value = value;
            }
            public override string ToString()
            {
                return Name;
            }
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (dgvOptions.SelectedRows.Count == 1)
            {
                var label = dgvOptions.SelectedRows[0].Cells[0].Value;
                var value = dgvOptions.SelectedRows[0].Cells[1].Value;
                var confirmMsg = string.Format("Are you sure you want to delete this option?{0}{0}Label: {1}{0}Value: {2}{0}{0}Please confirm...", Environment.NewLine, label, value);
                var msgResult = MessageBox.Show(confirmMsg, "Confirm delete.", MessageBoxButtons.YesNo);
                if (msgResult == DialogResult.Yes)
                {
                    dgvOptions.Rows.RemoveAt(dgvOptions.SelectedRows[0].Index);
                }
            }
            else if (dgvOptions.SelectedRows.Count > 1)
            {
                var confirmMsg = string.Format("Are you sure you want to delete all selected options?{0}{0}Please confirm...", Environment.NewLine);
                var msgResult = MessageBox.Show(confirmMsg, "Confirm delete.", MessageBoxButtons.YesNo);
                if (msgResult == DialogResult.Yes)
                {
                    foreach (DataGridViewRow item in dgvOptions.SelectedRows)
                    {
                        dgvOptions.Rows.RemoveAt(item.Index);
                    }
                }
            }
        }

        private void addOptionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var data = (BindingList<Item>)dgvOptions.DataSource;
            var newValue = data.Count > 0 ? int.Parse((from d in data select d.Value).OrderByDescending(k => k).FirstOrDefault()) + 1 : 1;
            data.Add(new Item("[enter label here]", newValue.ToString()));
            dgvOptions.DataSource = data;
        }

        private void moveUpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var data = (BindingList<Item>)dgvOptions.DataSource;
            var index = dgvOptions.SelectedRows[0].Index;
            var item = data[index];
            data.RemoveAt(index);
            data.Insert(index - 1, item);
            dgvOptions.DataSource = data;
        }

        private void moveDownToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var data = (BindingList<Item>)dgvOptions.DataSource;
            var index = dgvOptions.SelectedRows[0].Index;
            var item = data[index];
            data.RemoveAt(index);
            data.Insert(index + 1, item);
            dgvOptions.DataSource = data;
        }

        private void cmsOptionsGrid_Opening(object sender, CancelEventArgs e)
        {
            deleteToolStripMenuItem.Enabled = (dgvOptions.SelectedRows.Count > 0);
            moveUpToolStripMenuItem.Enabled = (dgvOptions.SelectedRows.Count == 1 && dgvOptions.SelectedRows[0].Index > 0);
            moveDownToolStripMenuItem.Enabled = (dgvOptions.SelectedRows.Count == 1 && dgvOptions.SelectedRows[0].Index < (dgvOptions.Rows.Count - 1));
        }

        private void copyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetDataObject(dgvOptions.GetClipboardContent());
        }

        private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DataObject o = (DataObject)Clipboard.GetDataObject();
            if (o.GetDataPresent(DataFormats.Text))
            {
                BindingList<Item> data = null;
                string[] pastedRows = Regex.Split(o.GetData(DataFormats.Text).ToString().TrimEnd("\r\n".ToCharArray()), "\r\n");
                foreach (string pastedRow in pastedRows)
                {
                    string[] pastedRowCells = pastedRow.Split(new char[] { '\t' });
                    if (dgvOptions.DataSource != null)
                    {
                        data = (BindingList<Item>)dgvOptions.DataSource;
                    }
                    else
                    {
                        data = new BindingList<Item>();
                    }

                    if (pastedRowCells.Length == 1)
                    {
                        var newValue = data.Count > 0 ? int.Parse((from d in data select d.Value).OrderByDescending(k => k).FirstOrDefault()) + 1 : 1;
                        data.Add(new Item(pastedRowCells[0], newValue.ToString()));
                    }
                    else if (pastedRowCells.Length > 1)
                    {
                        data.Add(new Item(pastedRowCells[0], pastedRowCells[1]));
                    }
                }
                if (data != null)
                {
                    dgvOptions.DataSource = data;
                }
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (chkIsGlobal.Checked)
            {
                SaveGlobalOptionSet();
            }
            else
            {
            }
        }

        private void SaveGlobalOptionSet()
        {
            WorkAsync("Saving global optionset...",
                (w, e) =>
                {
                    var req = new RetrieveOptionSetRequest()
                    {
                        Name = ((Item)cboOptionSets.SelectedItem).Value,
                    };
                    var resp = (RetrieveOptionSetResponse)Service.Execute(req);
                    OptionSetMetadata md = (OptionSetMetadata)resp.OptionSetMetadata;

                    //foreach (var option in md.Options)
                    //{
                    //    var delReq = new DeleteOptionValueRequest()
                    //    {
                    //        OptionSetName = md.Name,
                    //        Value = option.Value.Value
                    //    };
                    //    Service.Execute(delReq);
                    //}

                    var data = (BindingList<Item>)dgvOptions.DataSource;

                    var execMultiReq = new ExecuteMultipleRequest()
                    {
                        Settings = new Microsoft.Xrm.Sdk.ExecuteMultipleSettings()
                        {
                            ContinueOnError = true,
                            ReturnResponses = false
                        },
                        Requests = new Microsoft.Xrm.Sdk.OrganizationRequestCollection()
                    };

                    foreach (var item in data)
                    {
                        var exists = (from o in md.Options where o.Value.Value == int.Parse(item.Value) select true).FirstOrDefault();
                        if (exists)
                        {
                            var upReq = new UpdateOptionValueRequest()
                            {
                                OptionSetName = md.Name,
                                Label = new Microsoft.Xrm.Sdk.Label(item.Name, 1033),
                                Value = int.Parse(item.Value)
                            };
                            execMultiReq.Requests.Add(upReq);
                        }
                        else
                        {
                            var addReq = new InsertOptionValueRequest()
                            {
                                OptionSetName = md.Name,
                                Label = new Microsoft.Xrm.Sdk.Label(item.Name, 1033),
                                Value = int.Parse(item.Value)
                            };
                            execMultiReq.Requests.Add(addReq);
                        }
                    }

                    foreach (var item in md.Options)
                    {
                        var exists = (from d in data where int.Parse(d.Value) == item.Value.Value select true).FirstOrDefault();
                        if (!exists)
                        {
                            var delReq = new DeleteOptionValueRequest()
                            {
                                OptionSetName = md.Name,
                                Value = item.Value.Value
                            };
                            execMultiReq.Requests.Add(delReq);
                        }
                    }

                    Service.Execute(execMultiReq);

                    w.ReportProgress(50, "Publishing global optionset...");

                    PublishXmlRequest pxReq1 = new PublishXmlRequest { ParameterXml = String.Format("<importexportxml><optionsets><optionset>{0}</optionset></optionsets></importexportxml>", md.Name) };
                    Service.Execute(pxReq1);
                },
                e =>
                {
                },
                e =>
                {
                    SetWorkingMessage(e.UserState.ToString());
                }
            );
        }
    }
}
